﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;

namespace Sofire.Data
{
    /// <summary>
    /// 表示一个数据库交互的执行命令参数。
    /// </summary>
    [Serializable]
    public class ExecuteParameter : ICloneable
    {
        [NonSerialized]
        private DbParameter _SourceParameter;
        /// <summary>
        /// 获取原 <see cref="System.Data.Common.DbParameter"/> 实例。
        /// </summary>
        public DbParameter SourceParameter
        {
            get
            {
                return this._SourceParameter;
            }
        }

        private bool _IsValid = true;
        /// <summary>
        /// 设置或获取一个值，指示当前执行参数是否有效。如果为 false，则表示不添加到查询参数。默认为 true。
        /// </summary>
        public bool IsValid
        {
            get
            {
                return this._IsValid;
            }
            set
            {
                this._IsValid = value;
            }
        }

        private DbType? _Type;
        /// <summary>
        /// 获取或设置参数的 <see cref="System.Data.DbType"/>。
        /// <para>默认值为 <see cref="System.Data.DbType.String"/>。</para>
        /// </summary>
        public DbType Type
        {
            get
            {
                if(this._SourceParameter != null) return this._SourceParameter.DbType;
                if(this._Type.HasValue) return this._Type.Value;
                return DbType.String;
            }
            set
            {
                if(this._SourceParameter != null) this._SourceParameter.DbType = value;
                else this._Type = value;
            }
        }

        private int _Size = -1;
        /// <summary>
        /// 获取或设置参数的长度。
        /// <para>当值小于零时，默认值是从参数值推导出的。</para>
        /// </summary>
        public int Size
        {
            get
            {
                if(this._SourceParameter != null) return this._SourceParameter.Size;
                return this._Size;
            }
            set
            {
                if(this._SourceParameter != null) this._SourceParameter.Size = value;
                else this._Size = value;
            }
        }

        private ParameterDirection _Direction = ParameterDirection.Input;
        /// <summary>
        /// 获取或设置一个值，该值指示参数是只可输入、只可输出、双向还是存储过程返回值参数。
        /// <para>默认值为 <see cref="ParameterDirection.Input"/>。</para>
        /// </summary>
        public ParameterDirection Direction
        {
            get
            {
                if(this._SourceParameter != null) return this._SourceParameter.Direction;
                return this._Direction;
            }
            set
            {
                if(this._SourceParameter != null) this._SourceParameter.Direction = value;
                else this._Direction = value;
            }
        }

        private string _Name;
        /// <summary>
        /// 获取或设置参数的名称。
        /// </summary>
        public string Name
        {
            get
            {
                if(this._SourceParameter != null) return this._SourceParameter.ParameterName;
                return this._Name;
            }
            set
            {
                if(string.IsNullOrEmpty(value)) throw new ArgumentNullException("value");

                if(this._Owner != null)
                {
                    string oldName = this._SourceParameter == null ? this._Name : this._SourceParameter.ParameterName;
                    this._Owner.ChangedName(oldName, value);
                }

                if(this._SourceParameter != null) this._SourceParameter.ParameterName = value;
                else this._Name = value;
            }
        }

        private object _Value;
        /// <summary>
        /// 获取或设置参数的值。
        /// </summary>
        public object Value
        {
            get
            {
                if(this._SourceParameter != null) return this._SourceParameter.Value;
                return this._Value;
            }
            set
            {
                value = value ?? DBNull.Value;
                if(this._SourceParameter != null) this._SourceParameter.Value = value;
                else this._Value = value;
            }
        }

        [NonSerialized]
        private ExecuteParameterCollection _Owner;
        /// <summary>
        /// 获取参数所在的集合列表。
        /// </summary>
        public ExecuteParameterCollection Owner
        {
            get
            {
                return this._Owner;
            }
            internal set
            {
                this._Owner = value;
            }
        }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        public ExecuteParameter() { }

        /// <summary>
        /// 指定原 <see cref="System.Data.Common.DbParameter"/> 实例，初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="sourceParameter">原 <see cref="System.Data.Common.DbParameter"/> 实例。可以为 null，表示未确定数据。</param>
        public ExecuteParameter(DbParameter sourceParameter)
        {
            this._SourceParameter = sourceParameter;
        }

        /// <summary>
        /// 指定输出参数的名称，初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        public ExecuteParameter(string name)
            : this(name, null, null, -1, ParameterDirection.Output) { }

        /// <summary>
        /// 指定输出参数的名称和参数的类型，初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="type">参数的 <see cref="System.Data.DbType"/>。</param>
        public ExecuteParameter(string name, DbType type)
            : this(name, null, type, -1, ParameterDirection.Output) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        public ExecuteParameter(string name, object value)
            : this(name, value, null, -1, ParameterDirection.Input) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        /// <param name="direction">指示参数是只可输入、只可输出、双向还是存储过程返回值参数。</param>
        public ExecuteParameter(string name, object value, ParameterDirection direction)
            : this(name, value, null, -1, direction) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        /// <param name="type">参数的 <see cref="System.Data.DbType"/>。</param>
        public ExecuteParameter(string name, object value, DbType type)
            : this(name, value, type, -1, ParameterDirection.Input) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        /// <param name="type">参数的 <see cref="System.Data.DbType"/>。</param>
        /// <param name="size">参数的长度。</param>
        public ExecuteParameter(string name, object value, DbType type, int size)
            : this(name, value, type, size, ParameterDirection.Input) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        /// <param name="type">参数的 <see cref="System.Data.DbType"/>。</param>
        /// <param name="size">参数的长度。</param>
        /// <param name="direction">指示参数是只可输入、只可输出、双向还是存储过程返回值参数。</param>
        public ExecuteParameter(string name, object value, DbType type, int size, ParameterDirection direction)
            : this(name, value, (DbType?)type, size, direction) { }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.ExecuteParameter"/> 的新实例。
        /// </summary>
        /// <param name="name">参数的名称。</param>
        /// <param name="value">参数的值。</param>
        /// <param name="type">参数的 <see cref="System.Data.DbType"/>。</param>
        /// <param name="size">参数的长度。</param>
        /// <param name="direction">指示参数是只可输入、只可输出、双向还是存储过程返回值参数。</param>
        private ExecuteParameter(string name, object value, DbType? type, int size, ParameterDirection direction)
        {
            this.Name = name;
            this.Value = value;
            this._Type = type;
            this._Size = size;
            this._Direction = direction;
        }

        /// <summary>
        /// 指定 <see cref="System.Data.Common.DbCommand"/>，生成一个 <see cref="System.Data.Common.DbParameter"/>。
        /// </summary>
        /// <param name="command">一个 <see cref="System.Data.Common.DbCommand"/>。</param>
        /// <returns>返回一个已生成的 <see cref="System.Data.Common.DbParameter"/>。</returns>
        public DbParameter CreateParameter(DbCommand command)
        {
            if(command == null) throw new ArgumentNullException("command");
            if(this._SourceParameter != null)
            {
                return this._SourceParameter;
            }
            var parameter = command.CreateParameter();
            parameter.ParameterName = this._Name;
            parameter.Value = this._Value ?? DBNull.Value;
            if(this._Type.HasValue) parameter.DbType = this._Type.Value;
            if(this._Direction != ParameterDirection.Input) parameter.Direction = this._Direction;
            if(this._Size > -1) parameter.Size = this._Size;
            this._SourceParameter = parameter;
            return parameter;
        }

        #region ICloneable 成员

        /// <summary>
        /// 创建作为当前实例副本的新对象。
        /// </summary>
        /// <returns>作为此实例副本的新对象。</returns>
        public object Clone()
        {
            return new ExecuteParameter(this.Name, this.Value, this.Type, this.Size, this.Direction);
        }

        #endregion
    }

}
